﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Configuration;
using System.IO;

using oViT.FileWatcher;
//using System.Threading;

namespace oViT.FileMonitor
{
    public partial class MainWindow : Form
    {
        private string startupdirectory = Application.StartupPath;
        Watcher watcher;
        bool started = false;
        //Thread backgroundThread;
        //bool threadstarted = false;

        // events used to stop worker thread
        //ManualResetEvent m_EventStopThread;
        //ManualResetEvent m_EventThreadStopped;

        public MainWindow()
        {
            InitializeComponent();

            // initialize events
            //m_EventStopThread = new ManualResetEvent(false);
            //m_EventThreadStopped = new ManualResetEvent(false);

            txtPath.Text = (ConfigurationManager.AppSettings != null && ConfigurationManager.AppSettings["FolderPath"] != null ? ConfigurationManager.AppSettings["FolderPath"].ToString() : startupdirectory);
            txtFilter.Text = (ConfigurationManager.AppSettings != null && ConfigurationManager.AppSettings["Filter"] != null ? ConfigurationManager.AppSettings["Filter"].ToString() : "*.TiVo");
            chkSubFolders.Checked = (ConfigurationManager.AppSettings != null && ConfigurationManager.AppSettings["IncludeSubDirectories"] != null ? Boolean.Parse(ConfigurationManager.AppSettings["IncludeSubDirectories"].ToString()) : false);
            txtMAK.Text = (ConfigurationManager.AppSettings != null && ConfigurationManager.AppSettings["MAK"] != null ? ConfigurationManager.AppSettings["MAK"].ToString() : String.Empty);
            txtExt.Text = (ConfigurationManager.AppSettings != null && ConfigurationManager.AppSettings["DefaultFileExtension"] != null ? ConfigurationManager.AppSettings["DefaultFileExtension"].ToString() : "mpeg");
            txtOutput.Text = (ConfigurationManager.AppSettings != null && ConfigurationManager.AppSettings["OutputDirectory"] != null ? ConfigurationManager.AppSettings["OutputDirectory"].ToString() : startupdirectory);
            txtAppLoc.Text = (ConfigurationManager.AppSettings != null && ConfigurationManager.AppSettings["ApplicationPath"] != null ? ConfigurationManager.AppSettings["ApplicationPath"].ToString() : startupdirectory);
            chkProcessOnStartup.Checked = (ConfigurationManager.AppSettings != null && ConfigurationManager.AppSettings["ProcessOnStartup"] != null ? Boolean.Parse(ConfigurationManager.AppSettings["ProcessOnStartup"].ToString()) : false);
            chkStartOnStartup.Checked = (ConfigurationManager.AppSettings != null && ConfigurationManager.AppSettings["StartOnStartup"] != null ? Boolean.Parse(ConfigurationManager.AppSettings["StartOnStartup"].ToString()) : false);
            chkRemove.Checked = (ConfigurationManager.AppSettings != null && ConfigurationManager.AppSettings["RemoveProcessedFiles"] != null ? Boolean.Parse(ConfigurationManager.AppSettings["RemoveProcessedFiles"].ToString()) : false);

            if (chkStartOnStartup.Checked)
            {
                StartMonitor();
            }

            if (chkProcessOnStartup.Checked)
            {
                CheckAndProcessFiles();
            }
        }

        private void CheckAndProcessFiles()
        {
            StartMonitor();
        }

        /// <summary>
        /// initialize the folder monitor, assign the properties, add the events, and begin monitoring the folder
        /// </summary>
        private void StartMonitor()
        {
            if (!started)
            {
                // reset events
                //m_EventStopThread.Reset();
                //m_EventThreadStopped.Reset();

                //txtLog.Text += "Monitor started.\r\n";
                SetText("Monitor started.\r\n");

                SetText(String.Format("Monitoring folder: {0}\r\n", txtPath.Text));
                SetText(String.Format("Output folder: {0}\r\n", txtOutput.Text));

                if (watcher == null)
                {
                    watcher = new Watcher();

                    // set the watcher properties
                    watcher.ProcessPath = txtAppLoc.Text;
                    watcher.MAK = txtMAK.Text;
                    watcher.OutputDirectory = txtOutput.Text;
                    watcher.Extension = txtExt.Text;
                    watcher.RemoveFile = chkRemove.Checked;
                    watcher.ProcessOnStartup = chkProcessOnStartup.Checked;
                    watcher.FolderPath = txtPath.Text;
                    watcher.Filter = txtFilter.Text;
                    watcher.InclSubDirectories = chkSubFolders.Checked;

                    // add the events
                    watcher.FileCreated += new Watcher.WatcherEventHandler(watcher_FileCreated);
                    watcher.FileProcessed += new Watcher.WatcherProcessHandler(watcher_FileProcessed);
                }

                watcher.Start();

                /*if (backgroundThread == null)
                {
                    // crreate a thread and run the process in that
                    backgroundThread = new Thread(new ThreadStart(watcher.Start));
                    backgroundThread.Name = "FileProcessing";
                    backgroundThread.Start();
                }
                else
                {

                    if (!watcher.IsStarted)
                    {
                        lock (typeof(Watcher))
                        {
                            watcher.Start();
                        }
                    }
                //    backgroundThread.Name = "FileProcessing";
                //    backgroundThread.Start();
                }*/

                cmdStart.Enabled = false;
                cmdStop.Enabled = true;
                started = true;
                //threadstarted = true;
            }
        }

        /// <summary>
        /// start button command event handler - starts the folder monitor
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void cmdStart_Click(object sender, EventArgs e)
        {
            //if (!threadstarted)
            //{
            StartMonitor();
            //}
        }

        /// <summary>
        /// folder monitor event handler - writes the file processed output to the status window
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void watcher_FileProcessed(object sender, WatcherEventArgs e)
        {
            // Check if this method is running on a different thread
            // than the thread that created the control.
            if (this.txtLog.InvokeRequired)
            {
                // It's on a different thread, so use Invoke.
                SetTextCallback d = new SetTextCallback(SetText);
                this.Invoke
                    (d, new object[] { e.Output + "\r\n" });
            }
            else
            {
                // It's on the same thread, no need for Invoke
                //txtLog.Text += e.Output + "\r\n";
                SetText(e.Output + "\r\n");

            }
        }

        /// <summary>
        /// stop button command event handler - stops the folder monitor and writes a status message to the status window
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void cmdStop_Click(object sender, EventArgs e)
        {
            if (watcher != null)
            {
                //lock(typeof(Watcher)) 
                //{
                watcher.Stop();
                //txtLog.Text += "Monitor stopped.\r\n";
                SetText("Monitor stopped.\r\n");
                started = false;
                //}
            }



            /*if (backgroundThread != null && backgroundThread.IsAlive)
            {
                // set event "Stop"
                m_EventStopThread.Set();

                // wait when thread  will stop or finish
                while (backgroundThread.IsAlive)
                {
                    // We cannot use here infinite wait because our thread
                    // makes syncronous calls to main form, this will cause deadlock.
                    // Instead of this we wait for event some appropriate time
                    // (and by the way give time to worker thread) and
                    // process events. These events may contain Invoke calls.
                    if (WaitHandle.WaitAll(
                        (new ManualResetEvent[] { m_EventThreadStopped }),
                        100,
                        true))
                    {
                        break;
                    }

                    Application.DoEvents();
                }
            }*/
            cmdStart.Enabled = true;
            cmdStop.Enabled = false;
            //threadstarted = false;
            //backgroundThread = null;
            //backgroundThread.Abort();
            //backgroundThread.Join();
            //backgroundThread = null;

            //Thread.FreeNamedDataSlot("FileProcessing");
        }

        /// <summary>
        /// file created event handler - writes a status message to status window
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void watcher_FileCreated(object sender, FileSystemEventArgs e)
        {
            // Check if this method is running on a different thread
            // than the thread that created the control.
            if (this.txtLog.InvokeRequired)
            {
                // It's on a different thread, so use Invoke.
                SetTextCallback d = new SetTextCallback(SetText);
                this.Invoke
                    (d, new object[] { "Found new file to process : " + e.FullPath + "\r\nProcessing....\r\n" });
            }
            else
            {
                // It's on the same thread, no need for Invoke
                txtLog.Text += "Found new file to process : " + e.FullPath + "\r\nProcessing....\r\n";

            }
        }
        
        /// <summary>
        /// This method is passed in to the SetTextCallBack delegate to set the Text property of textBox
        /// </summary>
        /// <param name="text">string to pass to the status window</param>
        private void SetText(string text)
        {
            this.txtLog.Text += DateTime.Now.ToString() + ": " + text;
            this.txtLog.Focus();
            this.txtLog.Select(txtLog.TextLength, 0);
            this.txtLog.ScrollToCaret();
        }

        // This delegate enables asynchronous calls for setting
        // the text property on a TextBox control.
        delegate void SetTextCallback(string text);

        /// <summary>
        /// tool strip menu event handler - saves all user settings to the app.config file
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void saveToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (MessageBox.Show("Save settings?", "Confirm Save", MessageBoxButtons.YesNo) == DialogResult.Yes)
            {
                Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);

                if (config.AppSettings.Settings.Count == 0)
                {
                    CreateAppConfig();

                    config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
                }

                config.AppSettings.Settings["ProcessOnStartup"].Value = (chkProcessOnStartup == null ? "false" : chkProcessOnStartup.Checked.ToString());
                config.AppSettings.Settings["StartOnStartup"].Value = (chkStartOnStartup == null ? "false" : chkStartOnStartup.Checked.ToString());
                config.AppSettings.Settings["FolderPath"].Value = (txtPath == null ? "" : txtPath.Text);
                config.AppSettings.Settings["Filter"].Value = (txtFilter == null ? "" : txtFilter.Text);
                config.AppSettings.Settings["IncludeSubDirectories"].Value = chkSubFolders.Checked.ToString();
                config.AppSettings.Settings["MAK"].Value = (txtMAK == null ? "" : txtMAK.Text);
                config.AppSettings.Settings["OutputDirectory"].Value = (txtOutput == null ? "" : txtOutput.Text);
                config.AppSettings.Settings["DefaultFileExtension"].Value = (txtExt == null ? "" : txtExt.Text);
                config.AppSettings.Settings["ApplicationPath"].Value = (txtAppLoc == null ? "" : txtAppLoc.Text);
                config.AppSettings.Settings["RemoveProcessedFiles"].Value = (chkRemove == null ? "false" : chkRemove.Checked.ToString());

                config.Save(ConfigurationSaveMode.Modified);
                ConfigurationManager.RefreshSection("appSettings");
            }
        }

        /// <summary>
        /// exit the application
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Application.Exit();
        }

        /// <summary>
        /// set the output directory for the processed .mpeg files
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void cmdBrowseOutputDir_Click(object sender, EventArgs e)
        {
            // Show the FolderBrowserDialog.
            DialogResult result = folderBrowserDialog1.ShowDialog();
            if (result == DialogResult.OK)
            {
                txtOutput.Text = folderBrowserDialog1.SelectedPath;
            }
            // Cancel button was pressed.
            else if (result == DialogResult.Cancel)
            {
                return;
            }
        }

        /// <summary>
        /// set the TiVo Decoder application location
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void cmdBrowseAppLoc_Click(object sender, EventArgs e)
        {
            openFileDialog1.FileName = "";

            // Display the openFile dialog.
            DialogResult result = openFileDialog1.ShowDialog();

            // OK button was pressed.
            if (result == DialogResult.OK)
            {
                txtAppLoc.Text = openFileDialog1.FileName;
            }
            // Cancel button was pressed.
            else if (result == DialogResult.Cancel)
            {
                return;
            }
        }

        /// <summary>
        /// set whether the .tivo files are processed on app startup 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void chkProcessOnStartup_CheckedChanged(object sender, EventArgs e)
        {
            if (chkProcessOnStartup.Checked)
            {
                chkStartOnStartup.Checked = true;
            }
        }

        /// <summary>
        /// set the folder path to the source directory
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void cmdBrowseFolderPath_Click(object sender, EventArgs e)
        {
            // Show the FolderBrowserDialog.
            DialogResult result = folderBrowserDialog1.ShowDialog();
            if (result == DialogResult.OK)
            {
                txtPath.Text = folderBrowserDialog1.SelectedPath;
            }
            // Cancel button was pressed.
            else if (result == DialogResult.Cancel)
            {
                return;
            }
        }

        /// <summary>
        /// create the app.config file if not found or the values are missing
        /// </summary>
        private void CreateAppConfig()
        {
            // Specify config settings at runtime.
            Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
            //config.AppSettings.File = System.Reflection.Assembly.GetExecutingAssembly().GetName().Name + ".exe.Config2";
            config.AppSettings.Settings.Add("ProcessOnStartup", chkProcessOnStartup.Checked.ToString());
            config.AppSettings.Settings.Add("StartOnStartup", chkStartOnStartup.Checked.ToString());
            config.AppSettings.Settings.Add("FolderPath", startupdirectory);
            config.AppSettings.Settings.Add("Filter", txtFilter.Text);
            config.AppSettings.Settings.Add("IncludeSubDirectories", chkSubFolders.Checked.ToString());
            config.AppSettings.Settings.Add("MAK", txtMAK.Text);
            config.AppSettings.Settings.Add("OutputDirectory", startupdirectory);
            config.AppSettings.Settings.Add("DefaultFileExtension", txtExt.Text);
            config.AppSettings.Settings.Add("ApplicationPath", startupdirectory);
            config.AppSettings.Settings.Add("RemoveProcessedFiles", chkRemove.Checked.ToString());
            config.Save(ConfigurationSaveMode.Modified);
            ConfigurationManager.RefreshSection("appSettings");

        }

        /// <summary>
        /// display the about dialog box
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void aboutToolStripMenuItem_Click(object sender, EventArgs e)
        {
            AboutBox ab = new AboutBox();
            ab.ShowDialog();
        }

    }
}
